#ifndef _BATTERY_HPP__
#define _BATTERY_HPP__

#include <rclcpp/rclcpp.hpp>
#include "agv_msgs/msg/bat_info.hpp"
#include "agv_msgs/msg/agv_mode.hpp"
#include "std_msgs/msg/u_int64.hpp"
#include "std_msgs/msg/u_int8_multi_array.hpp"
#include "std_msgs/msg/u_int16_multi_array.hpp"
#include "std_msgs/msg/multi_array_dimension.hpp"
#include <thread>
#include <memory>
#include "event_manager.hpp"
#include "toolKit.hpp"

#define HEAD_NAME "/battery"

#define TOPICNAME "/topicName"
#define INDEX_OF_RAW "/index"
#define SCALE "/scale"  
#define OFFSET "/offset"
#define BYTE_LENGTH "/byte_length"    
#define TIMEOUT_S (10000)
#define CHARGE_CURRENT_DEFAULT 1.0

#define VOLTAGE "voltage"    
#define CURRENT "current"  
#define PERCENT "percent" 
#define TEMPERATURE "temperature" 
#define CYCLE_COUNTS "cycle_counts" 
#define HEALTH "health" 
#define BMS_STATE "bms_state" 
#define ERROR_CODE "error_code" 
#define TOTAL_CHARGE_AH "total_charge_ah" 
#define TOTAL_CHARGE_HOUR "total_charge_hour" 
#define TOTAL_RUN_HOUR "total_run_hour" 
#define NOMINAL_CAPACITY "nominal_capacity" 
#define CELL_TYPE "cell_type" 

enum CommunicationType
{
  CAN = 0,
  SERIAL,
};

enum Manufacturer
{ 
    TaitanType = 0,  
    HuokeType, 
    RebotType, 
    JunyunType,
    TaitanReverseType,
};

class CdataRecipe
{
public:
  float product_data_;
  CTimeStamp active_;
  
public:
  CdataRecipe() : product_data_(0.0f),
                  index_of_raw_data_(0),
                  byte_length_(0),
                  scale_(0.0f),
                  offset_(0.0f)
  {};
  
  ~CdataRecipe(){};
  
  void init(std::shared_ptr<rclcpp::Node> node, const std::string &prefix);
  
  float parser(const std_msgs::msg::UInt64 &msg) 
  {
    if (index_of_raw_data_ > 3) {
      RCLCPP_ERROR(rclcpp::get_logger("battery"), "index_of_raw_data_ should not greater than 3,(>3)");
      return 0.0f;
    }
    
    if (byte_length_ != 1 && byte_length_ != 2) {
      RCLCPP_ERROR(rclcpp::get_logger("battery"), "byte_length_ should be 1 or 2");
      return 0.0f;
    }

    int16_t clear_bits = byte_length_ == 2 ? 0xFFFF : 0x00FF;
    uint16_t shiftBit = index_of_raw_data_ * 16;
    int16_t rawTemp = (int16_t)(msg.data >> shiftBit) & clear_bits;
    return (rawTemp * scale_ + offset_);
  };

  float parser(const std_msgs::msg::UInt16MultiArray &msg) 
  {
    if (index_of_raw_data_ >= msg.data.size()) {
        RCLCPP_ERROR(rclcpp::get_logger("battery"), "index_of_raw_data_(%d) should not greater than raw data array size(%ld)", 
                    index_of_raw_data_, msg.data.size());
        return 0.0f;
    }
    
    int16_t raw = msg.data[index_of_raw_data_];
    return (raw * scale_ + offset_);
  };

  void can_parserCB(const std_msgs::msg::UInt64::SharedPtr msg);
  void rs485_parserCB(const std_msgs::msg::UInt16MultiArray::SharedPtr msg);
  
private:
  std::string topic_name;
  int index_of_raw_data_;
  int byte_length_;
  float scale_;
  float offset_;
  rclcpp::Subscription<std_msgs::msg::UInt64>::SharedPtr can_sub_;
  rclcpp::Subscription<std_msgs::msg::UInt16MultiArray>::SharedPtr rs485_sub_;
};


class CBattery
{
public:
  CBattery() : low_limit_(20),
               too_low_limit_(5),
               field_valid_(0)
  {
  };
  
  ~CBattery();

  bool haveData(std::string str); 
  bool createRecipe(std::string str); 
  void init(std::shared_ptr<rclcpp::Node> node); 
  void mode_Callback(const agv_msgs::msg::AGVMode::SharedPtr msg);
  void batteryLowcheck(void);
  void rawDataTimeoutCheck(void);
  bool TimeON(bool start, unsigned long duration_ms = 5000);

  bool timeout() {
      bool ret = false;
      for (const auto& pair : bat_paras_) {
          ret = ret || pair.second->active_.TimeOut(timeout_);
      }
      return ret;
  }

  bool isNew() {
      bool ret = true;
      for (const auto& pair : bat_paras_) {
          ret = ret && pair.second->active_.IsNew(timeout_);
      }
      return ret;
  }

  bool batteryInfo_update(void);
  
public:
  agv_msgs::msg::BatInfo battery_info_;  
  
private:
  std::shared_ptr<rclcpp::Node> node_;
  std::map<std::string, CdataRecipe*> bat_paras_;  // 使用指针存储
  CEventManager event_manager_;

  int low_limit_;
  int too_low_limit_;
  int timeout_;
  bool ignore_;   //忽略原始数据超时报警
  rclcpp::Subscription<agv_msgs::msg::AGVMode>::SharedPtr mode_sub_;
  float charge_current_;
  agv_msgs::msg::AGVMode agv_mode_;
  std::string cell_type_;   //电芯材料类型
  uint32_t field_valid_;   //电芯材料类型
};

#endif